/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年9月4日
 */
package com.massyframework.beanskin.runtime.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.ModuleDestoryingEvent;
import com.massyframework.beanskin.SimpleModuleIdentifier;
import com.massyframework.beanskin.framework.FrameworkDestroyingEvent;
import com.massyframework.beanskin.service.Filter;
import com.massyframework.beanskin.service.ServiceReference;
import com.massyframework.beanskin.service.ServiceRegistedEvent;
import com.massyframework.beanskin.service.ServiceRegistry;
import com.massyframework.beanskin.service.ServiceRepository;
import com.massyframework.beanskin.service.ServiceUnregistingEvent;
import com.massyframework.beanskin.util.classloading.ModuleClassLoader;

/**
 * {@link ServiceAdmin} 提供服务的注册、查询。
 */
final class ServiceAdmin  extends ServiceEventPublisher {

    private final ComparatorImpl comparator;
    private Map<Class<?>, CopyOnWriteArrayList<AbstractServiceRegistration<?>>> registrationMap;
    private Map<Long, AbstractServiceRegistration<?>> idMap;

    private Map<ModuleIdentifier, ServiceRegistryDelegate> registryMap ;
    private Map<ModuleIdentifier, ServiceRepositoryDelegate> repositoryMap;
    
    private volatile boolean destroying = false;
    
    /**
     * 构造方法
     */
    public ServiceAdmin(){
        super();

        this.registrationMap = new ConcurrentHashMap<>();
        this.idMap = new ConcurrentHashMap<>();
        this.comparator = new ComparatorImpl();

        this.registryMap  = new ConcurrentHashMap<>();
        this.repositoryMap = new ConcurrentHashMap<>();
    }

    /**
     * 根据{@code module}获取对应的{@link ServiceRepositoryDelegate}实例
     * @param module {@link ServiceExportableModule}, 支持服务输出的模块
     * @return {@link ServiceRepository}
     */
    public ServiceRepository getServiceRepository(Module<?> module){
    	ModuleIdentifier identifier =
    			SimpleModuleIdentifier.clone(module).build();
        return this.repositoryMap.computeIfAbsent(identifier,
                a -> new ServiceRepositoryDelegate(module, this));
    }

    /**
     * 根据<code>assembly</code>获取{@link ServiceRegistryDelegate}实例
     * @param module {@link Module}, 支持服务输出的模块
     * @return {@link ServiceRegistry}
     */
    protected ServiceRegistry getServiceRegistry(Module<?> module){
    	ModuleIdentifier identifier =
    			SimpleModuleIdentifier.clone(module).build();
        return this.registryMap.computeIfAbsent(identifier,
                a -> new ServiceRegistryDelegate(module, this));
    }

    /**
     * 全局模式下查找首个符合筛选条件的服务引用
     * @param filter {@link Filter}, 筛选器
     * @param module {@link Module}, 支持服务输出的模块
     * @return {@link ServiceReference}， 可能返回null.
     */
    @SuppressWarnings("unchecked")
    protected <S> ServiceReference<S> findServiceReference(Filter filter, Module<?> module) {
        Objects.requireNonNull(filter, "filter cannot be null.");

        for (List<AbstractServiceRegistration<?>> list: this.registrationMap.values()){
            for (AbstractServiceRegistration<?> registration: list){
                if (this.isMatch(registration, filter, module)){
                    return (ServiceReference<S>) registration.getServiceReference();
                }
            }
        }

        return null;
    }

    /**
     * 按服务类型和过滤条件，查找首个符合要求的服务引用
     * @param clazz {@link Class}, 服务类型
     * @param filter {@link Filter}, 服务过滤器
     * @param module {@link Module}, 发起查询请求的模块
     * @return {@link ServiceReference}输出服务引用
     */
    @SuppressWarnings("unchecked")
    protected <S> ServiceReference<S> findServiceReference(Class<S> clazz, Filter filter, Module<?> module) {
        Objects.requireNonNull(clazz, "clazz cannot be null.");
        Objects.requireNonNull(filter, "filter cannot be null.");

        List<AbstractServiceRegistration<?>> list =
                this.registrationMap.get(clazz);
        if (list != null){
            for (AbstractServiceRegistration<?> registration: list) {
                if (this.isMatch(registration, filter, module)){
                    return (ServiceReference<S>) registration.getServiceReference();
                }
            }
        }
        return null;
    }

    /**
     * 全局模式下查找所有满足筛选条件的服务引用
     * @param filter {@link Filter}, 服务过滤器
     * @param module {@link Module}, 发起查询请求的模块
     * @return {@link List}, 服务引用列表
     */
    protected List<ServiceReference<?>> getServiceReferences(Filter filter, Module<?> module) {
        Objects.requireNonNull(filter, "filter cannot be null.");
        List<ServiceReference<?>> result =
                new ArrayList<ServiceReference<?>>();
        for (List<AbstractServiceRegistration<?>> list: this.registrationMap.values()){
            for (AbstractServiceRegistration<?> registration: list){
                if (this.isMatch(registration, filter, module)){
                    result.add( registration.getServiceReference());
                }
            }
        }

        return result;
    }

    /**
     * 按服务类型和过滤条件，查找所有符合要求的服务引用
     * @param clazz {@link Class},服务类型
     * @param filter {@link Filter}, 过滤器
     * @param module {@link Module}, 发起查询请求的模块
     * @return {@link List}输出服务引用集合
     */
    @SuppressWarnings({ "unchecked" })
    protected <S> List<ServiceReference<S>> getServiceReferences(
            Class<S> clazz, Filter filter, Module<?> module) {
        Objects.requireNonNull(clazz, "clazz cannot be null.");
        Objects.requireNonNull(filter, "filter cannot be null.");

        List<ServiceReference<S>> result = new ArrayList<>();
        List<AbstractServiceRegistration<?>> list =
                this.registrationMap.get(clazz);
        if (list != null){
            for (AbstractServiceRegistration<?> registration: list) {
                if (this.isMatch(registration, filter, module)){
                    result.add((ServiceReference<S>) registration.getServiceReference());
                }
            }
        }
        return result;
    }

    /**
     * 根据<code>reference</code>和<code>assembly</code>查询服务实例
     * @param reference {@link ServiceReference}, 服务引用
     * @param module {@link Module}, 查询服务的模块
     * @return {@link S}
     */
    @SuppressWarnings("unchecked")
    protected <S> S getService(ServiceReference<S> reference, Module<?> module){
        if (reference == null) return null;
        if (module == null) return null;

        long id = reference.getServiceId();
        AbstractServiceRegistration<?> registration = idMap.get(id);
        if (registration != null){
            return (S) registration.getService(module);
        }
        return null;
    }

    /**
     * 判断<code>registration</code>是否满足<code>filter</code>匹配要求
     * @param registration, {@link AbstractServiceRegistration}
     * @param filter {@link Filter}, 过滤器
     * @param module {@link Module}, 发起查询的模块
     * @return {@link boolean}, 返回<code>true</code>表示匹配，否则返回<code>false</code>
     */
    protected boolean isMatch(AbstractServiceRegistration<?> registration, Filter filter, Module<?> module){
        ServiceReference<?> reference = registration.getServiceReference();
        return filter.match(reference);
    }
    
    /**
     * 模块卸载事件处理
     * @param event
     */
    protected void onEvent(ModuleDestoryingEvent event) {
    	Module<?> module = event.getModule();
    	ModuleClassLoader classLoader = module.getModuleClassLoader();
    	List<Class<?>>  classes = this.registrationMap.keySet().stream()
    			.filter( clazz -> clazz.getClassLoader() == classLoader)
    			.collect(Collectors.toList());
    	if (!classes.isEmpty()) {
    		for (Class<?> clazz: classes) {
    			CopyOnWriteArrayList<AbstractServiceRegistration<?>> list = this.registrationMap.get(clazz);
    			if (list != null) {
    				for (AbstractServiceRegistration<?> registration: list) {
    					//强制卸载.
    					registration.unregister(true);
    				}
    			}
    			
    			this.registrationMap.remove(clazz);
    		}
    	}
    			
    	
    	List<AbstractServiceRegistration<?>> found =
    		this.idMap.values().stream()
    			.filter( registration-> {
    				return registration.isMatch(module, classLoader);
    			})
    			.collect(Collectors.toList());
    	
    	if (!found.isEmpty()) {
    		for (AbstractServiceRegistration<?> registration: found) {
    			registration.unregister();
    		}
    	}
    }
    
    protected void onEvent(FrameworkDestroyingEvent event) {
    	this.destroying = true;
    }
    
    /**
     * 是否处于销毁阶段
     * <br>
     * 插件注册的服务，仅只能在销毁阶段注销
     * @return {@link boolean},返回{@code true}表示是.
     */
    protected boolean isDestroying() {
    	return this.destroying;
    }

    /**
     * 所有服务类型的列表
     * @return {@link List},服务类型列表
     */
    protected List<Class<?>> getServiceTypes(){
        List<Class<?>> result =
                new ArrayList<Class<?>>(this.registrationMap.keySet());
        return result;
    }
    
    /**
     * 添加{@link AbstractServiceRegistration}
     * @param registration {@link AbstractServiceRegistration}
     * @param moudule {@link Module}, 注册服务的模块
     */
    void addRegistration(AbstractServiceRegistration<?> registration, Module<?> module){
        ServiceReference<?> reference =
                registration.getServiceReference();
        Class<?>[] serviceTypes =
                reference.getExportTypes();
        for (Class<?> serviceType: serviceTypes){
            CopyOnWriteArrayList<AbstractServiceRegistration<?>> list =
                    this.registrationMap.computeIfAbsent(serviceType,
                            type -> {
                                return new CopyOnWriteArrayList<AbstractServiceRegistration<?>>();
                            });

            //按次序添加到列表
            this.addInOrder(list, registration, this.comparator);
        }

        this.idMap.put(reference.getServiceId(), registration);        
        Logger logger = this.getLogger();
        if (logger != null){
            if (logger.isInfoEnabled()){
                String message = new StringBuilder()
                        .append("register service ")
                        .append(Arrays.toString(serviceTypes))
                        .append(" success.")
                        .toString();
                logger.info(message);
            }
        }

        //发布服务注册事件
        ServiceRegistedEvent<?> event = new ServiceRegistedEvent<>(reference);
        this.applyEvent(event, registration.getAllowAccess());
    }

    /**
     * 移除{@link AbstractServiceRegistration}
     * @param registration {@link AbstractServiceRegistration}
     * @param module {@link Module}, 取消服务注册的模块
     */
    boolean removeRegistration(AbstractServiceRegistration<?> registration, Module<?> module){
        ServiceReference<?> reference =
                registration.getServiceReference();
        if (this.idMap.containsKey(reference.getServiceId())){
            //先发布服务注销事件
            ServiceUnregistingEvent<?> event = new ServiceUnregistingEvent<>(reference);
           	this.applyEvent(event, registration.getAllowAccess());

            this.idMap.remove(reference.getServiceId());
            Class<?>[] serviceTypes =
                    reference.getExportTypes();
            for (Class<?> serviceType: serviceTypes){
                CopyOnWriteArrayList<AbstractServiceRegistration<?>> list = this.registrationMap.get(serviceType);
                if (list != null){
                    list.remove(registration);
                }
            }

            Logger logger = this.getLogger();
            if (logger != null){
                if (logger.isInfoEnabled()){
                    String message = new StringBuilder()
                            .append("remove service ")
                            .append(Arrays.toString(serviceTypes))
                            .append(" success.")
                            .toString();
                    logger.info(message);
                }
            }
            
            return true;
        }
        
        return false;
    }

    /**
     * 将<code>item</code>按排序添加到<code>list</code>集合中
     *
     * @param list {@link CopyOnWriteArrayList}实例
     * @param item 待加入<code>list</code>的元素
     * @param comparator 比较器，用于计算<code>item</code>在<code>list</code>中的排序
     * @return {@link int},返回<code>item</code>加入<code>list</code>后的排序号.
     */
    private <T> int addInOrder(final CopyOnWriteArrayList<T> list, final T item,
                               final Comparator<T> comparator) {
        final int insertAt;
        // The index of the search key, if it is contained in the list; otherwise,
        // (-(insertion point) - 1)
        final int index = Collections.binarySearch(list, item, comparator);
        if (index < 0) {
            insertAt = -(index + 1);
        } else {
            insertAt = index + 1;
        }

        list.add(insertAt, item);
        return insertAt;
    }
    
  
	protected void unregister(Module<?> module) {
    	if (module == null) return;
    	String identifier = module.toIdentifier();
    	
		List<AbstractServiceRegistration<?>> registrations =
				this.idMap.values().stream()
					.filter( registration -> 
						registration.getServiceReference().getModuleIdentifier().equals(identifier)
					)
					.collect(Collectors.toList());
		for (AbstractServiceRegistration<?> registration: registrations) {
			registration.unregister();
		}
	}



	/**
     * AbstractServiceRegistration 比较器
     */
    private class ComparatorImpl implements Comparator<AbstractServiceRegistration<?>> {

        /**
         * Compares its two arguments for order. Returns a negative integer, zero, or a
         * positive integer as the first argument is less than, equal to, or greater
         * than the second.
         * <p>
         * <p>
         * The implementor must ensure that {@code sgn(compare(x, y)) ==
         * -sgn(compare(y, x))} for all {@code x} and {@code y}. (This implies that
         * {@code compare(x, y)} must throw an exception if and only if
         * {@code compare(y, x)} throws an exception.)
         * <p>
         * <p>
         * The implementor must also ensure that the relation is transitive:
         * {@code ((compare(x, y)>0) && (compare(y, z)>0))} implies
         * {@code compare(x, z)>0}.
         * <p>
         * <p>
         * Finally, the implementor must ensure that {@code compare(x, y)==0} implies
         * that {@code sgn(compare(x, z))==sgn(compare(y, z))} for all {@code z}.
         * <p>
         * <p>
         * It is generally the case, but <i>not</i> strictly required that
         * {@code (compare(x, y)==0) == (x.equals(y))}. Generally speaking, any
         * comparator that violates this condition should clearly indicate this fact.
         * The recommended language is "Note: this comparator imposes orderings that are
         * inconsistent with equals."
         * <p>
         * <p>
         * In the foregoing description, the notation
         * {@code sgn(}<i>expression</i>{@code )} designates the mathematical
         * <i>signum</i> function, which is defined to return one of {@code -1},
         * {@code 0}, or {@code 1} according to whether the value of <i>expression</i>
         * is negative, zero, or positive, respectively.
         *
         * @param o1 the first object to be compared.
         * @param o2 the second object to be compared.
         * @return a negative integer, zero, or a positive integer as the first argument
         *         is less than, equal to, or greater than the second.
         * @throws NullPointerException if an argument is null and this comparator does
         *                              not permit null arguments
         * @throws ClassCastException   if the arguments' types prevent them from being
         *                              compared by this comparator.
         */
        @Override
        public int compare(AbstractServiceRegistration<?> o1, AbstractServiceRegistration<?> o2) {
            ServiceReference<?> reference1 = o1.getServiceReference();
            ServiceReference<?> reference2 = o2.getServiceReference();

            //先比较service.name
            String name1 = reference1.getServiceName();
            String name2 = reference2.getServiceName();

            int result = StringUtils.compare(name1, name2);
            if (result == 0){
                //再比较排序
                int o1_ranking = reference1.getServiceRanking();
                int o2_ranking = reference2.getServiceRanking();

                result = Integer.compare(o2_ranking, o1_ranking);
                if (result == 0) {                	
                	if (result == 0) {
                		result = Long.compare(reference1.getServiceId(), reference2.getServiceId());
                	}
                }
            }

            return result;
        }
    }
}

